home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / tcp / clients / atcp_ttcp10.lha / ttcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-10  |  20.2 KB  |  907 lines

  1. /*
  2.  *    T T C P . C
  3.  *
  4.  * Test TCP connection.  Makes a connection on port 5001
  5.  * and transfers fabricated buffers or data copied from stdin.
  6.  *
  7.  * Usable on 4.2, 4.3, and 4.1a systems by defining one of
  8.  * BSD42 BSD43 (BSD41a)
  9.  * Machines using System V with BSD sockets should define SYSV.
  10.  *
  11.  * Modified for operation under 4.2BSD, 18 Dec 84
  12.  *      T.C. Slattery, USNA
  13.  * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
  14.  * Modified in 1989 at Silicon Graphics, Inc.
  15.  *    catch SIGPIPE to be able to print stats when receiver has died 
  16.  *    for tcp, don't look for sentinel during reads to allow small transfers
  17.  *    increased default buffer size to 8K, nbuf to 2K to transfer 16MB
  18.  *    moved default port to 5001, beyond IPPORT_USERRESERVED
  19.  *    make sinkmode default because it is more popular, 
  20.  *        -s now means don't sink/source 
  21.  *    count number of read/write system calls to see effects of 
  22.  *        blocking from full socket buffers
  23.  *    for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt)
  24.  *    buffer alignment options, -A and -O
  25.  *    print stats in a format that's a bit easier to use with grep & awk
  26.  *    for SYSV, mimic BSD routines to use most of the existing timing code
  27.  * Modified by Steve Miller of the University of Maryland, College Park
  28.  *    -b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF)
  29.  * Modified Sept. 1989 at Silicon Graphics, Inc.
  30.  *    restored -s sense at request of tcs@brl
  31.  * Modified Oct. 1991 at Silicon Graphics, Inc.
  32.  *    use getopt(3) for option processing, add -f and -T options.
  33.  *    SGI IRIX 3.3 and 4.0 releases don't need #define SYSV.
  34.  * Modified Oct. 1993 ch
  35.  *      Added rudimentary amiga support.
  36.  *      Removed rusage stuff for amigados.
  37.  *
  38.  * Distribution Status -
  39.  *      Public Domain.  Distribution Unlimited.
  40.  */
  41. #ifndef lint
  42. static char RCSid[] = "ttcp.c $Revision: 1.2 $";
  43. #endif
  44.  
  45. #define BSD43
  46. /* #define BSD42 */
  47. /* #define BSD41a */
  48. /* #define SYSV */    /* required on SGI IRIX releases before 3.3 */
  49.  
  50. #include <stdio.h>
  51. #include <signal.h>
  52. #include <ctype.h>
  53. #include <errno.h>
  54. #include <sys/types.h>
  55. #include <sys/socket.h>
  56. #include <netinet/in.h>
  57. #if defined(amigados)
  58. #include <sys/param.h>
  59. #endif
  60. #include <netinet/tcp.h>
  61. #include <arpa/inet.h>
  62. #include <netdb.h>
  63. #include <sys/time.h>        /* struct timeval */
  64.  
  65. #if defined(SYSV)
  66. #include <sys/times.h>
  67. #include <sys/param.h>
  68. struct rusage {
  69.     struct timeval ru_utime, ru_stime;
  70. };
  71. #define RUSAGE_SELF 0
  72. #elif  defined(amigados)
  73. #else
  74. #include <sys/resource.h>
  75. #endif
  76.  
  77. #if defined(amigados)
  78. #include <stdlib.h>
  79. #include <string.h>
  80. #include <fcntl.h>
  81. #include "amiga/s_socket.h"
  82. /* FIXME */
  83. typedef long time_t;
  84. /* TTCP.C */
  85. void sigpipe ( void );
  86. int main ( int argc , char **argv );
  87. void err ( char *s );
  88. void mes ( char *s );
  89. int pattern ( char *cp , int cnt );
  90. char *outfmt ( double b );
  91. void prep_timer ( void );
  92. static void
  93. prusage(struct timeval *e, struct timeval *b, char *outp);
  94. double read_timer ( char *str , int len );
  95. static void tvadd ( struct timeval *tsum , struct timeval *t0 , struct timeval *t1 );
  96. static void tvsub ( struct timeval *tdiff , struct timeval *t1 , struct timeval *t0 );
  97. static void psecs ( long l , char *cp );
  98. int Nread ( int fd , void *buf , int count );
  99. int Nwrite ( int fd , void *buf , int count );
  100. void delay ( int us );
  101. int mread ( int fd , char *bufp , unsigned n );
  102. #endif
  103.  
  104.  
  105. struct sockaddr_in sinme;
  106. struct sockaddr_in sinhim;
  107. struct sockaddr_in frominet;
  108.  
  109. int domain, fromlen;
  110. int fd;                /* fd of network socket */
  111.  
  112. int buflen = 8 * 1024;        /* length of buffer */
  113. char *buf;            /* ptr to dynamic buffer */
  114. int nbuf = 2 * 1024;        /* number of buffers to send in sinkmode */
  115.  
  116. int bufoffset = 0;        /* align buffer to this */
  117. int bufalign = 16*1024;        /* modulo this */
  118.  
  119. int udp = 0;            /* 0 = tcp, !0 = udp */
  120. int options = 0;        /* socket options */
  121. int one = 1;                    /* for 4.3 BSD style setsockopt() */
  122. short port = 5001;        /* TCP port number */
  123. char *host;            /* ptr to name of host */
  124. int trans;            /* 0=receive, !0=transmit mode */
  125. int sinkmode = 0;        /* 0=normal I/O, !0=sink/source mode */
  126. int verbose = 0;        /* 0=print basic info, 1=print cpu rate, proc
  127.                  * resource usage. */
  128. int nodelay = 0;        /* set TCP_NODELAY socket option */
  129. int b_flag = 0;            /* use mread() */
  130. int sockbufsize = 0;        /* socket buffer size to use */
  131. char fmt = 'K';            /* output format: k = kilobits, K = kilobytes,
  132.                  *  m = megabits, M = megabytes, 
  133.                  *  g = gigabits, G = gigabytes */
  134. int touchdata = 0;        /* access data after reading */
  135.  
  136. struct hostent *addr;
  137. extern int errno;
  138. extern int optind;
  139. extern char *optarg;
  140.  
  141. char Usage[] = "\
  142. Usage: ttcp -t [-options] host [ < in ]\n\
  143.        ttcp -r [-options > out]\n\
  144. Common options:\n\
  145.     -l ##    length of bufs read from or written to network (default 8192)\n\
  146.     -u    use UDP instead of TCP\n\
  147.     -p ##    port number to send to or listen at (default 5001)\n\
  148.     -s    -t: source a pattern to network\n\
  149.         -r: sink (discard) all data from network\n\
  150.     -A    align the start of buffers to this modulus (default 16384)\n\
  151.     -O    start buffers at this offset from the modulus (default 0)\n\
  152.     -v    verbose: print more statistics\n\
  153.     -d    set SO_DEBUG socket option\n\
  154.     -b ##    set socket buffer size (if supported)\n\
  155.     -f X    format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\
  156. Options specific to -t:\n\
  157.     -n##    number of source bufs written to network (default 2048)\n\
  158.     -D    don't buffer TCP writes (sets TCP_NODELAY socket option)\n\
  159. Options specific to -r:\n\
  160.     -B    for -s, only output full blocks as specified by -l (for TAR)\n\
  161.     -T    \"touch\": access each byte as it's read\n\
  162. ";    
  163.  
  164. char stats[128];
  165. unsigned long nbytes;        /* bytes on net */
  166. unsigned long numCalls;        /* # of I/O system calls */
  167. double cput, realt;        /* user, real time (seconds) */
  168.  
  169. void err();
  170. void mes();
  171. int pattern();
  172. void prep_timer();
  173. double read_timer();
  174. int Nread();
  175. int Nwrite();
  176. void delay();
  177. int mread();
  178. char *outfmt();
  179.  
  180. void
  181. sigpipe()
  182. {
  183. }
  184.  
  185. main(argc,argv)
  186. int argc;
  187. char **argv;
  188. {
  189.     unsigned long addr_tmp;
  190.     int c;
  191.  
  192.     if (argc < 2) goto usage;
  193.  
  194.     while ((c = getopt(argc, argv, "drstuvBDTb:f:l:n:p:A:O:")) != -1) {
  195.         switch (c) {
  196.  
  197.         case 'B':
  198.             b_flag = 1;
  199.             break;
  200.         case 't':
  201.             trans = 1;
  202.             break;
  203.         case 'r':
  204.             trans = 0;
  205.             break;
  206.         case 'd':
  207.             options |= SO_DEBUG;
  208.             break;
  209.         case 'D':
  210. #ifdef TCP_NODELAY
  211.             nodelay = 1;
  212. #else
  213.             fprintf(stderr, 
  214.     "ttcp: -D option ignored: TCP_NODELAY socket option not supported\n");
  215. #endif
  216.             break;
  217.         case 'n':
  218.             nbuf = atoi(optarg);
  219.             break;
  220.         case 'l':
  221.             buflen = atoi(optarg);
  222.             break;
  223.         case 's':
  224.             sinkmode = !sinkmode;
  225.             break;
  226.         case 'p':
  227.             port = atoi(optarg);
  228.             break;
  229.         case 'u':
  230.             udp = 1;
  231.             break;
  232.         case 'v':
  233.             verbose = 1;
  234.             break;
  235.         case 'A':
  236.             bufalign = atoi(optarg);
  237.             break;
  238.         case 'O':
  239.             bufoffset = atoi(optarg);
  240.             break;
  241.         case 'b':
  242. #if defined(SO_SNDBUF) || defined(SO_RCVBUF)
  243.             sockbufsize = atoi(optarg);
  244. #else
  245.             fprintf(stderr, 
  246. "ttcp: -b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported\n");
  247. #endif
  248.             break;
  249.         case 'f':
  250.             fmt = *optarg;
  251.             break;
  252.         case 'T':
  253.             touchdata = 1;
  254.             break;
  255.  
  256.         default:
  257.             goto usage;
  258.         }
  259.     }
  260.     if(trans)  {
  261.         /* xmitr */
  262.         if (optind == argc)
  263.             goto usage;
  264.         bzero((char *)&sinhim, sizeof(sinhim));
  265.         host = argv[optind];
  266.         if (atoi(host) > 0 )  {
  267.             /* Numeric */
  268.             sinhim.sin_family = AF_INET;
  269. #if defined(cray)
  270.             addr_tmp = inet_addr(host);
  271.             sinhim.sin_addr = addr_tmp;
  272. #else
  273.             sinhim.sin_addr.s_addr = inet_addr(host);
  274. #endif
  275.         } else {
  276.             if ((addr=gethostbyname(host)) == NULL)
  277.                 err("bad hostname");
  278.             sinhim.sin_family = addr->h_addrtype;
  279.             bcopy(addr->h_addr,(char*)&addr_tmp, addr->h_length);
  280. #if defined(cray)
  281.             sinhim.sin_addr = addr_tmp;
  282. #else
  283.             sinhim.sin_addr.s_addr = addr_tmp;
  284. #endif /* cray */
  285.         }
  286.         sinhim.sin_port = htons(port);
  287.         sinme.sin_port = 0;        /* free choice */
  288.     } else {
  289.         /* rcvr */
  290.         sinme.sin_port =  htons(port);
  291.     }
  292.  
  293.  
  294.     if (udp && buflen < 5) {
  295.         buflen = 5;        /* send more than the sentinel size */
  296.     }
  297.  
  298.     if ( (buf = (char *)malloc(buflen+bufalign)) == (char *)NULL)
  299.         err("malloc");
  300.     if (bufalign != 0)
  301.         buf +=(bufalign - ((int)buf % bufalign) + bufoffset) % bufalign;
  302.  
  303.     if (trans) {
  304.         fprintf(stdout,
  305.         "ttcp-t: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
  306.         buflen, nbuf, bufalign, bufoffset, port);
  307.          if (sockbufsize)
  308.          fprintf(stdout, ", sockbufsize=%d", sockbufsize);
  309.          fprintf(stdout, "  %s  -> %s\n", udp?"udp":"tcp", host);
  310.     } else {
  311.         fprintf(stdout,
  312.          "ttcp-r: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
  313.          buflen, nbuf, bufalign, bufoffset, port);
  314.          if (sockbufsize)
  315.          fprintf(stdout, ", sockbufsize=%d", sockbufsize);
  316.          fprintf(stdout, "  %s\n", udp?"udp":"tcp");
  317.     }
  318.  
  319.     if ((fd = socket(AF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0)) < 0)
  320.         err("socket");
  321.     mes("socket");
  322.  
  323.     if (bind(fd, &sinme, sizeof(sinme)) < 0)
  324.         err("bind");
  325.  
  326. #if defined(SO_SNDBUF) || defined(SO_RCVBUF)
  327.     if (sockbufsize) {
  328.         if (trans) {
  329.         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
  330.             sizeof sockbufsize) < 0)
  331.             err("setsockopt: sndbuf");
  332.         mes("sndbuf");
  333.         } else {
  334.         if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize,
  335.             sizeof sockbufsize) < 0)
  336.             err("setsockopt: rcvbuf");
  337.         mes("rcvbuf");
  338.         }
  339.     }
  340. #endif
  341.  
  342.     if (!udp)  {
  343. #ifdef SIGPIPE
  344.         signal(SIGPIPE, sigpipe);
  345. #endif
  346.         if (trans) {
  347.         /* We are the client if transmitting */
  348.         if (options)  {
  349. #if defined(BSD42)
  350.             if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  351. #else /* BSD43 */
  352.             if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  353. #endif
  354.                 err("setsockopt");
  355.         }
  356. #ifdef TCP_NODELAY
  357.         if (nodelay) {
  358.             struct protoent *p;
  359.             p = getprotobyname("tcp");
  360.             if( p && setsockopt(fd, p->p_proto, TCP_NODELAY, 
  361.                 &one, sizeof(one)) < 0)
  362.                 err("setsockopt: nodelay");
  363.             mes("nodelay");
  364.         }
  365. #endif
  366.         if(connect(fd, &sinhim, sizeof(sinhim) ) < 0)
  367.             err("connect");
  368.         mes("connect");
  369.         } else {
  370.         /* otherwise, we are the server and 
  371.              * should listen for the connections
  372.              */
  373.         listen(fd,0);   /* allow a queue of 0 */
  374.         if(options)  {
  375. #if defined(BSD42)
  376.             if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  377. #else /* BSD43 */
  378.             if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  379. #endif
  380.                 err("setsockopt");
  381.         }
  382.         fromlen = sizeof(frominet);
  383.         domain = AF_INET;
  384.         if((fd=accept(fd, &frominet, &fromlen) ) < 0)
  385.             err("accept");
  386.         { struct sockaddr_in peer;
  387.           int peerlen = sizeof(peer);
  388.           if (getpeername(fd, (struct sockaddr_in *) &peer, 
  389.                 &peerlen) < 0) {
  390.             err("getpeername");
  391.           }
  392.           fprintf(stderr,"ttcp-r: accept from %s\n", 
  393.             inet_ntoa(peer.sin_addr));
  394.         }
  395.         }
  396.     }
  397.     prep_timer();
  398.     errno = 0;
  399.     if (sinkmode) {      
  400.         register int cnt;
  401.         if (trans)  {
  402.             pattern( buf, buflen );
  403.             if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr start */
  404.             while (nbuf-- && Nwrite(fd,buf,buflen) == buflen)
  405.                 nbytes += buflen;
  406.             if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  407.         } else {
  408.             if (udp) {
  409.                 while ((cnt=Nread(fd,buf,buflen)) > 0)  {
  410.                     static int going = 0;
  411.                     if( cnt <= 4 )  {
  412.                         if( going )
  413.                             break;    /* "EOF" */
  414.                         going = 1;
  415.                         prep_timer();
  416.                     } else {
  417.                         nbytes += cnt;
  418.                     }
  419.                 }
  420.             } else {
  421.                 while ((cnt=Nread(fd,buf,buflen)) > 0)  {
  422.                     nbytes += cnt;
  423.                 }
  424.             }
  425.         }
  426.     } else {
  427.         register int cnt;
  428.         if (trans)  {
  429.             while((cnt=read(0,buf,buflen)) > 0 &&
  430.                 Nwrite(fd,buf,cnt) == cnt)
  431.                 nbytes += cnt;
  432.         }  else  {
  433.             while((cnt=Nread(fd,buf,buflen)) > 0 &&
  434.                 write(1,buf,cnt) == cnt)
  435.                 nbytes += cnt;
  436.         }
  437.     }
  438.     if(errno) err("IO");
  439.     (void)read_timer(stats,sizeof(stats));
  440.     if(udp&&trans)  {
  441.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  442.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  443.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  444.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  445.     }
  446.     if( cput <= 0.0 )  cput = 0.001;
  447.     if( realt <= 0.0 )  realt = 0.001;
  448.     fprintf(stdout,
  449.         "ttcp%s: %ld bytes in %.2f real seconds = %s/sec +++\n",
  450.         trans?"-t":"-r",
  451.         nbytes, realt, outfmt(((double)nbytes)/realt));
  452.     if (verbose) {
  453.         fprintf(stdout,
  454.         "ttcp%s: %ld bytes in %.2f CPU seconds = %s/cpu sec\n",
  455.         trans?"-t":"-r",
  456.         nbytes, cput, outfmt(((double)nbytes)/cput));
  457.     }
  458.     fprintf(stdout,
  459.         "ttcp%s: %d I/O calls, msec/call = %.2f, calls/sec = %.2f\n",
  460.         trans?"-t":"-r",
  461.         numCalls,
  462.         1024.0 * realt/((double)numCalls),
  463.         ((double)numCalls)/realt);
  464.     fprintf(stdout,"ttcp%s: %s\n", trans?"-t":"-r", stats);
  465.     if (verbose) {
  466.         fprintf(stdout,
  467.         "ttcp%s: buffer address %#x\n",
  468.         trans?"-t":"-r",
  469.         buf);
  470.     }
  471.     exit(0);
  472.  
  473. usage:
  474.     fprintf(stderr,Usage);
  475.     exit(1);
  476. }
  477.  
  478. void
  479. err(s)
  480. char *s;
  481. {
  482.     fprintf(stderr,"ttcp%s: ", trans?"-t":"-r");
  483.     perror(s);
  484.     fprintf(stderr,"errno=%d\n",errno);
  485.     exit(1);
  486. }
  487.  
  488. void
  489. mes(s)
  490. char *s;
  491. {
  492.     fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", s);
  493. }
  494.  
  495. pattern( cp, cnt )
  496. register char *cp;
  497. register int cnt;
  498. {
  499.     register char c;
  500.     c = 0;
  501.     while( cnt-- > 0 )  {
  502.         while( !isprint((c&0x7F)) )  c++;
  503.         *cp++ = (c++&0x7F);
  504.     }
  505. }
  506.  
  507. char *
  508. outfmt(b)
  509. double b;
  510. {
  511.     static char obuf[50];
  512.     switch (fmt) {
  513.     case 'G':
  514.         sprintf(obuf, "%.2f GB", b / 1024.0 / 1024.0 / 1024.0);
  515.         break;
  516.     default:
  517.     case 'K':
  518.         sprintf(obuf, "%.2f KB", b / 1024.0);
  519.         break;
  520.     case 'M':
  521.         sprintf(obuf, "%.2f MB", b / 1024.0 / 1024.0);
  522.         break;
  523.     case 'g':
  524.         sprintf(obuf, "%.2f Gbit", b * 8.0 / 1024.0 / 1024.0 / 1024.0);
  525.         break;
  526.     case 'k':
  527.         sprintf(obuf, "%.2f Kbit", b * 8.0 / 1024.0);
  528.         break;
  529.     case 'm':
  530.         sprintf(obuf, "%.2f Mbit", b * 8.0 / 1024.0 / 1024.0);
  531.         break;
  532.     }
  533.     return obuf;
  534. }
  535.  
  536. static struct    timeval time0;    /* Time at which timing started */
  537. #ifndef amigados
  538. static struct    rusage ru0;    /* Resource utilization at the start */
  539. #endif
  540.  
  541. static void prusage();
  542. static void tvadd();
  543. static void tvsub();
  544. static void psecs();
  545.  
  546. #if defined(SYSV)
  547. /*ARGSUSED*/
  548. static
  549. getrusage(ignored, ru)
  550.     int ignored;
  551.     register struct rusage *ru;
  552. {
  553.     struct tms buf;
  554.  
  555.     times(&buf);
  556.  
  557.     /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */
  558.     ru->ru_stime.tv_sec  = buf.tms_stime / HZ;
  559.     ru->ru_stime.tv_usec = ((buf.tms_stime % HZ) * 1000000) / HZ;
  560.     ru->ru_utime.tv_sec  = buf.tms_utime / HZ;
  561.     ru->ru_utime.tv_usec = ((buf.tms_utime % HZ) * 1000000) / HZ;
  562. }
  563. #endif
  564.  
  565. #if defined(SYSV)
  566. /*ARGSUSED*/
  567. static 
  568. gettimeofday(tp, zp)
  569.     struct timeval *tp;
  570.     struct timezone *zp;
  571. {
  572.     tp->tv_sec = time(0);
  573.     tp->tv_usec = 0;
  574. }
  575. #endif /* SYSV */
  576.  
  577. /*
  578.  *            P R E P _ T I M E R
  579.  */
  580. void
  581. prep_timer()
  582. {
  583.     gettimeofday(&time0, (struct timezone *)0);
  584. #ifndef amigados
  585.     getrusage(RUSAGE_SELF, &ru0);
  586. #endif
  587. }
  588.  
  589. /*
  590.  *            R E A D _ T I M E R
  591.  * 
  592.  */
  593. double
  594. read_timer(str,len)
  595. char *str;
  596. {
  597.     struct timeval timedol;
  598. #ifndef amigados
  599.     struct rusage ru1;
  600.     struct timeval tend, tstart;
  601. #endif
  602.     struct timeval td;
  603.     char line[132];
  604.  
  605. #ifndef amigados
  606.     getrusage(RUSAGE_SELF, &ru1);
  607.     gettimeofday(&timedol, (struct timezone *)0);
  608.     prusage(&ru0, &ru1, &timedol, &time0, line);
  609. #else
  610.     gettimeofday(&timedol, (struct timezone *)0);
  611.     prusage(&timedol, &time0, line);
  612. #endif
  613.     (void)strncpy( str, line, len );
  614.  
  615.     /* Get real time */
  616.     tvsub( &td, &timedol, &time0 );
  617.     realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
  618.  
  619.     /* Get CPU time (user+sys) */
  620. #ifndef amigados
  621.     tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime );
  622.     tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime );
  623.     tvsub( &td, &tend, &tstart );
  624.     cput = td.tv_sec + ((double)td.tv_usec) / 1000000;
  625.     if( cput < 0.00001 )  cput = 0.00001;
  626. #else
  627.     cput = 0.0;
  628. #endif
  629.     return( cput );
  630. }
  631.  
  632. #ifdef amigados
  633. static void
  634. prusage(struct timeval *e, struct timeval *b, char *outp)
  635. #else
  636. static void
  637. prusage(r0, r1, e, b, outp)
  638.     register struct rusage *r0, *r1;
  639.     struct timeval *e, *b;
  640.     char *outp;
  641. #endif
  642. {
  643. #ifndef amigados
  644.     struct timeval tdiff;
  645.     register time_t t;
  646.     register int i;
  647. #endif
  648.     register char *cp;
  649.     int ms;
  650.  
  651. #ifndef amigados
  652.     t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+
  653.         (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+
  654.         (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+
  655.         (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000;
  656. #endif
  657.     ms =  (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000;
  658.  
  659. #define END(x)    {while(*x) x++;}
  660. #if defined amigados
  661.     cp = "%Ereal";
  662. #else
  663. #if defined(SYSV)
  664.     cp = "%Uuser %Ssys %Ereal %P";
  665. #else
  666. #if defined(sgi)        /* IRIX 3.3 will show 0 for %M,%F,%R,%C */
  667.     cp = "%Uuser %Ssys %Ereal %P %Mmaxrss %F+%Rpf %Ccsw";
  668. #else
  669.     cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";
  670. #endif
  671. #endif
  672. #endif
  673.     for (; *cp; cp++)  {
  674.         if (*cp != '%')
  675.             *outp++ = *cp;
  676.         else if (cp[1]) switch(*++cp) {
  677.  
  678. #ifndef amigados
  679.             case 'U':
  680.             tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime);
  681.             sprintf(outp,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000);
  682.             END(outp);
  683.             break;
  684.  
  685.         case 'S':
  686.             tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
  687.             sprintf(outp,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000);
  688.             END(outp);
  689.             break;
  690. #endif
  691.         case 'E':
  692.             psecs(ms / 100, outp);
  693.             END(outp);
  694.             break;
  695. #ifndef amigados
  696.         case 'P':
  697.             sprintf(outp,"%d%%", (int) (t*100 / ((ms ? ms : 1))));
  698.             END(outp);
  699.             break;
  700.  
  701. #if !defined(SYSV) && !defined(__SASC)
  702.         case 'W':
  703.             i = r1->ru_nswap - r0->ru_nswap;
  704.             sprintf(outp,"%d", i);
  705.             END(outp);
  706.             break;
  707.  
  708.         case 'X':
  709.             sprintf(outp,"%d", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t);
  710.             END(outp);
  711.             break;
  712.  
  713.         case 'D':
  714.             sprintf(outp,"%d", t == 0 ? 0 :
  715.                 (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t);
  716.             END(outp);
  717.             break;
  718.  
  719.         case 'K':
  720.             sprintf(outp,"%d", t == 0 ? 0 :
  721.                 ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) -
  722.                 (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t);
  723.             END(outp);
  724.             break;
  725.  
  726.         case 'M':
  727.             sprintf(outp,"%d", r1->ru_maxrss/2);
  728.             END(outp);
  729.             break;
  730.  
  731.         case 'F':
  732.             sprintf(outp,"%d", r1->ru_majflt-r0->ru_majflt);
  733.             END(outp);
  734.             break;
  735.  
  736.         case 'R':
  737.             sprintf(outp,"%d", r1->ru_minflt-r0->ru_minflt);
  738.             END(outp);
  739.             break;
  740.  
  741.         case 'I':
  742.             sprintf(outp,"%d", r1->ru_inblock-r0->ru_inblock);
  743.             END(outp);
  744.             break;
  745.  
  746.         case 'O':
  747.             sprintf(outp,"%d", r1->ru_oublock-r0->ru_oublock);
  748.             END(outp);
  749.             break;
  750.         case 'C':
  751.             sprintf(outp,"%d+%d", r1->ru_nvcsw-r0->ru_nvcsw,
  752.                 r1->ru_nivcsw-r0->ru_nivcsw );
  753.             END(outp);
  754.             break;
  755. #endif /* !SYSV */
  756. #endif /* !amigados */
  757.         }
  758.     }
  759.     *outp = '\0';
  760. }
  761.  
  762. static void
  763. tvadd(tsum, t0, t1)
  764.     struct timeval *tsum, *t0, *t1;
  765. {
  766.  
  767.     tsum->tv_sec = t0->tv_sec + t1->tv_sec;
  768.     tsum->tv_usec = t0->tv_usec + t1->tv_usec;
  769.     if (tsum->tv_usec > 1000000)
  770.         tsum->tv_sec++, tsum->tv_usec -= 1000000;
  771. }
  772.  
  773. static void
  774. tvsub(tdiff, t1, t0)
  775.     struct timeval *tdiff, *t1, *t0;
  776. {
  777.  
  778.     tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  779.     tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  780.     if (tdiff->tv_usec < 0)
  781.         tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  782. }
  783.  
  784. static void
  785. psecs(l,cp)
  786. long l;
  787. register char *cp;
  788. {
  789.     register int i;
  790.  
  791.     i = l / 3600;
  792.     if (i) {
  793.         sprintf(cp,"%d:", i);
  794.         END(cp);
  795.         i = l % 3600;
  796.         sprintf(cp,"%d%d", (i/60) / 10, (i/60) % 10);
  797.         END(cp);
  798.     } else {
  799.         i = l;
  800.         sprintf(cp,"%d", i / 60);
  801.         END(cp);
  802.     }
  803.     i %= 60;
  804.     *cp++ = ':';
  805.     sprintf(cp,"%d%d", i / 10, i % 10);
  806. }
  807.  
  808. /*
  809.  *            N R E A D
  810.  */
  811. Nread( fd, buf, count )
  812. int fd;
  813. void *buf;
  814. int count;
  815. {
  816.     struct sockaddr_in from;
  817.     int len = sizeof(from);
  818.     register int cnt;
  819.     if( udp )  {
  820.         cnt = recvfrom( fd, buf, count, 0, &from, &len );
  821.         numCalls++;
  822.     } else {
  823.         if( b_flag )
  824.             cnt = mread( fd, buf, count );    /* fill buf */
  825.         else {
  826.             cnt = read( fd, buf, count );
  827.             numCalls++;
  828.         }
  829.         if (touchdata && cnt > 0) {
  830.             register int c = cnt, sum=0;
  831.             register char *b = buf;
  832.             while (c--)
  833.                 sum += *b++;
  834.         }
  835.     }
  836.     return(cnt);
  837. }
  838.  
  839. /*
  840.  *            N W R I T E
  841.  */
  842. Nwrite( fd, buf, count )
  843. int fd;
  844. void *buf;
  845. int count;
  846. {
  847.     register int cnt;
  848.     if( udp )  {
  849. again:
  850.         cnt = sendto( fd, buf, count, 0, &sinhim, sizeof(sinhim) );
  851.         numCalls++;
  852.         if( cnt<0 && errno == ENOBUFS )  {
  853.             delay(18000);
  854.             errno = 0;
  855.             goto again;
  856.         }
  857.     } else {
  858.         cnt = write( fd, buf, count );
  859.         numCalls++;
  860.     }
  861.     return(cnt);
  862. }
  863.  
  864. void
  865. delay(us)
  866. {
  867.     struct timeval tv;
  868.  
  869.     tv.tv_sec = 0;
  870.     tv.tv_usec = us;
  871.     (void)select( 1, (char *)0, (char *)0, (char *)0, &tv );
  872. }
  873.  
  874. /*
  875.  *            M R E A D
  876.  *
  877.  * This function performs the function of a read(II) but will
  878.  * call read(II) multiple times in order to get the requested
  879.  * number of characters.  This can be necessary because
  880.  * network connections don't deliver data with the same
  881.  * grouping as it is written with.  Written by Robert S. Miles, BRL.
  882.  */
  883. int
  884. mread(fd, bufp, n)
  885. int fd;
  886. register char    *bufp;
  887. unsigned    n;
  888. {
  889.     register unsigned    count = 0;
  890.     register int        nread;
  891.  
  892.     do {
  893.         nread = read(fd, bufp, n-count);
  894.         numCalls++;
  895.         if(nread < 0)  {
  896.             perror("ttcp_mread");
  897.             return(-1);
  898.         }
  899.         if(nread == 0)
  900.             return((int)count);
  901.         count += (unsigned)nread;
  902.         bufp += nread;
  903.      } while(count < n);
  904.  
  905.     return((int)count);
  906. }
  907.